package com.scarecrow.olga.task {
	
	import com.scarecrow.olga.core.controller.TaskController;
	import com.scarecrow.olga.task.event.TaskEvent;
	import com.scarecrow.olga.util.logging.Logger;
	import flash.events.EventDispatcher;
	import flash.utils.getQualifiedClassName;
	
	[Event(name = "taskFailure", type = "com.scarecrow.olga.task.event.TaskEvent")]
	
	[Event(name = "taskCancelled", type = "com.scarecrow.olga.task.event.TaskEvent")]
	
	[Event(name = "taskComplete", type = "com.scarecrow.olga.task.event.TaskEvent")]
	
	[Event(name = "taskPaused", type = "com.scarecrow.olga.task.event.TaskEvent")]
	
	[Event(name = "taskResumed", type = "com.scarecrow.olga.task.event.TaskEvent")]
	
	/**
	 * This class represents a task, which is a series of logic operations to be performed application-wise
	 * at high or low level. A Task object has access to game models and core elements so that implementation
	 * of generalized logic can be encapsulated here.
	 * 
	 * All tasks are managed by the TaskController, which enforces that no two tasks of the same type overlap
	 * with each other. This is done to improve organization of sequential task groups.
	 * ...
	 * @author Santiago.J.Elizalde
	 */
	public class Task extends EventDispatcher {
		
		
		//Task types
		public static const GENERIC_TASK:String = "genericTask";
		
		protected var taskType:String;
		protected var paused:Boolean = false;
		
		public function Task() {
			taskType = Task.GENERIC_TASK;
		}
		
		/**
		 * Begins execution of the task. The task is registered on the TaskController at this moment.
		 */
		public function execute():void {
			TaskController.registerTask(this);
		}
		
		/**
		 * Executes the needed logic when the task has failed. The taskController will throw an error with
		 * the task failure if on strict mode.
		 * 
		 * @param	failureCause the reason why the task has failed to complete.
		 */
		protected function fail(failureCause:String = "unknown"):void {
			if (paused) {
				Logger.log("Task '" + getQualifiedClassName(this) + "' failed while being paused.", Logger.LOG_LEVEL_WARN);
			}
			dispatchEvent(new TaskEvent(TaskEvent.TASK_FAILURE, this, failureCause));
		}
		
		/**
		 * Cancels the task, removing it from the controller and usually rolling back the changes performed.
		 * 
		 * @param	cancellationCause the reason why the task was cancelled.
		 */
		protected function cancel(cancellationCause:String = "unknown"):void {
			if (paused) {
				Logger.log("Task '" + getQualifiedClassName(this) + "' was cancelled while being paused.", Logger.LOG_LEVEL_WARN);
			}
			dispatchEvent(new TaskEvent(TaskEvent.TASK_CANCELLED, this, cancellationCause));
		}
		
		/**
		 * Handles the task's successful end. All closure operations are performed by this function, 
		 * and a TASK_COMPLETE event is fired.
		 */
		protected function finish():void {
			if (paused) {
				Logger.log("Task '" + getQualifiedClassName(this) + "' was finished while being paused.", Logger.LOG_LEVEL_WARN);
			}
			dispatchEvent(new TaskEvent(TaskEvent.TASK_COMPLETE, this));
		}
		
	   /**
		* Pauses the task. While a task is paused, other tasks of the same time can be executed.
		*/
		protected function pause():void {
			if (!paused) {
				paused = true;
				dispatchEvent(new TaskEvent(TaskEvent.TASK_PAUSED, this));
			} else {
				Logger.log("Task '" + getQualifiedClassName(this) + "' was paused when being already paused.", Logger.LOG_LEVEL_WARN);
			}
		}
		
		/**
		 * Resumes the task's execution.
		 */
		protected function resume():void {
			if(paused) {
				paused = false;
				dispatchEvent(new TaskEvent(TaskEvent.TASK_RESUMED, this));
			} else {
				Logger.log("Task '" + getQualifiedClassName(this) + "' was resumed without being paused.", Logger.LOG_LEVEL_WARN);
			}
		}
		
		public function get type():String {
			return taskType;
		}
		
		override public function toString():String {
			return getQualifiedClassName(this);
		}
	}
}